/*
 * This is the source code of Telegram for Android v. 5.x.x.
 * It is licensed under GNU GPL v. 2 or later.
 * You should have received a copy of the license in this archive (see LICENSE).
 *
 * Copyright Nikolai Kudashov, 2013-2018.
 */

package com.ansion.string;

import android.util.Pair;

import java.util.ArrayList;

public class Emoji {


    public static class EmojiSpanRange {
        public EmojiSpanRange(int start, int end, CharSequence code) {
            this.start = start;
            this.end = end;
            this.code = code;
        }

        public int start;
        public int end;
        public CharSequence code;
    }

    public static boolean fullyConsistsOfEmojis(CharSequence cs) {
        int[] emojiOnly = new int[1];
        parseEmojis(cs, emojiOnly);
        return emojiOnly[0] > 0;
    }

    public static ArrayList<EmojiSpanRange> parseEmojis(CharSequence cs) {
        return parseEmojis(cs, null);
    }

    public static String takeFirstCharacter(String text) {
        ArrayList<EmojiSpanRange> ranges = Emoji.parseEmojis(text);
        if (ranges != null && !ranges.isEmpty() && ranges.get(0).start == 0) {
            return text.substring(0, ranges.get(0).end);
        }
        return text.substring(0, text.offsetByCodePoints(0, Math.min(text.codePointCount(0, text.length()), 1)));
    }

    public static Pair<Boolean, String> takeFirstCharacterPair(String text) {
        ArrayList<EmojiSpanRange> ranges = Emoji.parseEmojis(text);
        if (ranges != null && !ranges.isEmpty() && ranges.get(0).start == 0) {
            return new Pair<>(true, text.substring(0, ranges.get(0).end));
        }
        return new Pair<>(false, text.substring(0, text.offsetByCodePoints(0, Math.min(text.codePointCount(0, text.length()), 1))));
    }

    public static ArrayList<EmojiSpanRange> parseEmojis(CharSequence cs, int[] emojiOnly) {
        ArrayList<EmojiSpanRange> emojis = new ArrayList<>();
        if (cs == null || cs.length() <= 0) {
            return emojis;
        }
        long buf = 0;
        char c;
        int startIndex = -1;
        int startLength = 0;
        int previousGoodIndex = 0;
        StringBuilder emojiCode = new StringBuilder(16);
        int length = cs.length();
        boolean doneEmoji = false;
        boolean notOnlyEmoji;

        try {
            for (int i = 0; i < length; i++) {
                c = cs.charAt(i);
                notOnlyEmoji = false;
                if (c >= 0xD83C && c <= 0xD83E || (buf != 0 && (buf & 0xFFFFFFFF00000000L) == 0 && (buf & 0xFFFF) == 0xD83C && (c >= 0xDDE6 && c <= 0xDDFF))) {
                    if (startIndex == -1) {
                        startIndex = i;
                    }
                    emojiCode.append(c);
                    startLength++;
                    buf <<= 16;
                    buf |= c;
                } else if (emojiCode.length() > 0 && (c == 0x2640 || c == 0x2642 || c == 0x2695)) {
                    emojiCode.append(c);
                    startLength++;
                    buf = 0;
                    doneEmoji = true;
                } else if (buf > 0 && (c & 0xF000) == 0xD000) {
                    emojiCode.append(c);
                    startLength++;
                    buf = 0;
                    doneEmoji = true;
                } else if (c == 0x20E3) {
                    if (i > 0) {
                        char c2 = cs.charAt(previousGoodIndex);
                        if ((c2 >= '0' && c2 <= '9') || c2 == '#' || c2 == '*') {
                            startIndex = previousGoodIndex;
                            startLength = i - previousGoodIndex + 1;
                            emojiCode.append(c2);
                            emojiCode.append(c);
                            doneEmoji = true;
                        }
                    }
                } else if ((c == 0x00A9 || c == 0x00AE || c >= 0x203C && c <= 0x3299) && EmojiData.dataCharsMap.containsKey(c)) {
                    if (startIndex == -1) {
                        startIndex = i;
                    }
                    startLength++;
                    emojiCode.append(c);
                    doneEmoji = true;
                } else if (startIndex != -1) {
                    emojiCode.setLength(0);
                    startIndex = -1;
                    startLength = 0;
                    doneEmoji = false;
                } else if (c != 0xfe0f && c != '\n' && c != ' ' && c != '\t') {
                    notOnlyEmoji = true;
                }
                if (doneEmoji && i + 2 < length) {
                    char next = cs.charAt(i + 1);
                    if (next == 0xD83C) {
                        next = cs.charAt(i + 2);
                        if (next >= 0xDFFB && next <= 0xDFFF) {
                            emojiCode.append(cs.subSequence(i + 1, i + 3));
                            startLength += 2;
                            i += 2;
                        }
                    } else if (emojiCode.length() >= 2 && emojiCode.charAt(0) == 0xD83C && emojiCode.charAt(1) == 0xDFF4 && next == 0xDB40) {
                        i++;
                        while (true) {
                            emojiCode.append(cs.charAt(i)).append(cs.charAt(i + 1));
                            startLength += 2;
                            i += 2;
                            if (i >= cs.length() || cs.charAt(i) != 0xDB40) {
                                i--;
                                break;
                            }
                        }
                    }
                }
                previousGoodIndex = i;
                char prevCh = c;
                for (int a = 0; a < 3; a++) {
                    if (i + 1 < length) {
                        c = cs.charAt(i + 1);
                        if (a == 1) {
                            if (c == 0x200D && emojiCode.length() > 0) {
                                notOnlyEmoji = false;
                                emojiCode.append(c);
                                i++;
                                startLength++;
                                doneEmoji = false;
                            }
                        } else if (startIndex != -1 || prevCh == '*' || prevCh == '#' || prevCh >= '0' && prevCh <= '9') {
                            if (c >= 0xFE00 && c <= 0xFE0F) {
                                i++;
                                startLength++;
                                if (!doneEmoji) {
                                    doneEmoji = i + 1 >= length;
                                }
                            }
                        }
                    }
                }
                if (notOnlyEmoji && emojiOnly != null) {
                    emojiOnly[0] = 0;
                    emojiOnly = null;
                }
                if (doneEmoji && i + 2 < length && cs.charAt(i + 1) == 0xD83C) {
                    char next = cs.charAt(i + 2);
                    if (next >= 0xDFFB && next <= 0xDFFF) {
                        emojiCode.append(cs.subSequence(i + 1, i + 3));
                        startLength += 2;
                        i += 2;
                    }
                }
                if (doneEmoji) {
                    if (emojiOnly != null) {
                        emojiOnly[0]++;
                    }
                    emojis.add(new EmojiSpanRange(startIndex, startIndex + startLength, emojiCode.subSequence(0, emojiCode.length())));
                    startLength = 0;
                    startIndex = -1;
                    emojiCode.setLength(0);
                    doneEmoji = false;
                }
            }
        } catch (Exception e) {
//            FileLog.e(e);
        }
        if (emojiOnly != null && emojiCode.length() != 0) {
            emojiOnly[0] = 0;
        }
        return emojis;
    }


}
